use chrono::{prelude::*, Duration};
use jsonwebtoken::{encode, decode,  Header, Algorithm, Validation, EncodingKey, DecodingKey, errors::ErrorKind};
use axum::Json;
use serde::{Serialize, Deserialize};
use serde_json::{ json, Value };
use dotenv::dotenv;
use std::env;
use crate::{code, uuid, query};

#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    exp: i64,
    pub id: i32,
    pub cid: Option<i32>,
    pub role: Option<i32>,
    pub ident: String,
    pub casc: Option<String>,
    pub veri: String,
    pub uuid: String
}
pub fn token_encode(id:i32, cid:Option<i32>, role:Option<i32>,ident:String, casc:Option<String>, veri:String, uid:Option<String>) -> Result<String, Json<Value>>{
    dotenv().ok();
    let env_expire = env::var("EXPIRE_WX").unwrap_or_default();
    let expire = if env_expire.is_empty() { config::EXPIRE as i64 } else { env_expire.parse::<i64>().unwrap_or(0) };

    let now: DateTime<Local> = Local::now();
    let exp: DateTime<Local> = now + Duration::seconds(expire);
    let exp: i64 = exp.timestamp();
    if ident.is_empty() || veri.is_empty(){
        return Err(code::err_("加密数据不存在"));
    }
    let auto_uuid = if uid.is_none() { uuid::create() } else { uid.unwrap() };
    let claims:Claims = Claims{
        exp: exp,
        id:id,
        cid:cid,
        role:role,
        ident: ident,
        veri: veri,
        casc: casc,
        uuid: auto_uuid
    };
    let header: Header = Header::new(Algorithm::HS512);
    match encode(
        &header,
        &claims,
        &EncodingKey::from_secret("secret".as_ref())
    ){
        Ok(t) => Ok(String::from("Bearer ") + &t),
        Err(_) => Err(code::err_("token 加密失败"))
    }
}

pub fn token_decode(token:Option<&str>, is_exp:bool) -> Result<Claims, Json<Value>>{
    if token.is_none() {
        return Err(code::err_("token 不存在"));
    }
    let mut validation: Validation = Validation::new(Algorithm::HS512);
    validation.validate_exp = is_exp;
    validation.leeway = 0;
    let mut token = token.unwrap().split_whitespace();

    match token.nth(1) {
        Some(token) =>{
            // validation.insecure_disable_signature_validation();
            match decode::<Claims>(
                token,                                            
                &DecodingKey::from_secret("secret".as_ref()),
                &validation
            ){
                Ok(f) => {
                    let claims = &mut json!(f.claims);
                    let claims:Claims = Claims {
                        exp: query::i64(claims, "exp")?, 
                        id: query::i32(claims, "id")?,
                        cid: query::i32_op(claims, "cid")?, 
                        role: query::i32_op(claims, "role")?, 
                        ident: query::str(claims, "ident")?,
                        casc: query::str_op(claims, "casc")?,
                        veri: query::str(claims, "veri")?,
                        uuid: query::str(claims, "uuid")?
                    };
                    Ok(claims)
                },
                Err(err) => {
                    match *err.kind() {
                        ErrorKind::InvalidAlgorithm => Err(code::sys_("token 无效算法")),
                        ErrorKind::InvalidSignature => Err(code::sys_("token 无效签名")),
                        ErrorKind::InvalidAudience=> Err(code::err_code_msg_(201,"token 无效听众")),
                        ErrorKind::InvalidIssuer => Err(code::err_code_msg_(201,"token 无效签发者")),
                        ErrorKind::InvalidSubject => Err(code::err_code_msg_(201,"token 无效用户")),
                        ErrorKind::InvalidToken => Err(code::err_code_msg_(201,"无效 token")),
                        ErrorKind::ExpiredSignature => Err(code::err_code_msg_(202,"token 过期")),
                        ErrorKind::InvalidKeyFormat => Err(code::err_("token 密钥格式无效")),
                        _ => Err(code::err_("token 解密失败"))
                    }
                }
            }
        },
        None => Err(code::err_("token 不存在"))
    }
}